
#include "etl_server_socket.h"

using namespace etl;

etl_server_socket::etl_server_socket() : 
    prototype( NULL ), 
    port( 0 ), 
    started( false )
{
}

etl_server_socket::~etl_server_socket()
{
    delete prototype;
}

int etl_server_socket::set_port( int p )
{
    if( p )
    {
        port = p;
        return etl_socket::SOK_SUCCESS;
    }
    return -1;
}

int etl_server_socket::attach_connection_prototype( etl_connection_base* proto )
{
    if( proto )
    {
        prototype = proto->clone();
        return etl_socket::SOK_SUCCESS;
    }

    return etl_socket::SOK_FAILURE;
}

int etl_server_socket::start()
{
    if( prototype && (port != 0) )
    {
        started = true;

        if (server_sok.create() != etl_socket::SOK_SUCCESS)
            return etl_socket::SOK_FAILURE;
        if (server_sok.bind(port) != etl_socket::SOK_SUCCESS)
            return etl_socket::SOK_FAILURE;
        if (server_sok.listen() != etl_socket::SOK_SUCCESS)
            return etl_socket::SOK_FAILURE;

        while( started )
        {
            if( server_sok.ready_to_recv( 100 ) )
            {
                // create a new connection object...
                etl_connection_base* new_connection = prototype->clone();

                // accept this incoming connection....
                server_sok.accept(new_connection->client_conn);

                // adding a connection to our active connection pool...
                active_connections.append(new_connection);

                new_connection->running = true;

                pthread_create(&new_connection->thread, 
                               NULL,
                               etl_server_socket::connection_launcher, 
                               new_connection);
            }

            prune_old_connections();
        }
    }

    return etl_socket::SOK_FAILURE;
}

int etl_server_socket::stop()
{
    started = false;

    // should we prune ALL open connections?

    return etl_socket::SOK_SUCCESS;
}

int etl_server_socket::prune_old_connections()
{
    static long conns = 0;
    active_connections.iter_begin();

    while( active_connections.iter_valid() )
    {
        bool auto_advanced = false;
        etl_connection_base* conn = *active_connections.iter_data();
        if( conn && (conn->running == false) )
	{
            void* ret_val = NULL;
            pthread_join( conn->thread, &ret_val );
            active_connections.remove_at_iter();
            delete conn;
            conns++;
            auto_advanced = true;
	}
        if( auto_advanced == false )
            active_connections.iter_next();
    }
    return etl_socket::SOK_SUCCESS;
}

void* etl_server_socket::connection_launcher(void* arg)
{
    if (arg)
    {
        etl_connection_base* conn = (etl_connection_base*) arg;
        conn->service_client();
        conn->running = false;
        conn->client_conn.shutdown( SHUT_WR );
    }

    return NULL;
}

int etl_server_socket::get_sok_id()
{
    return server_sok.get_sok_id();
}
